# -*- coding: UTF-8 -*-
# server_assets
# @File : BattleStateMachine.py
# @Date : 2023-08-30
# @Author  : wuzhouhai
# @Desc:
import KBEngine
from KBEDebug import *

import copy
import s_skillBuff
import ConstantDefine

# 新增结算类型
BUFF_CLEARING_TYPE_NEW = [ConstantDefine.DEFINE_BUFF_SUB_TYPE_ADD_ATT,
                          ConstantDefine.DEFINE_BUFF_SUB_TYPE_REDUCE_ATT,
                          ConstantDefine.DEFINE_BUFF_SUB_TYPE_ADD_ARMOR,
                          ConstantDefine.DEFINE_BUFF_SUB_TYPE_WEAKEN_RECOVER_HP,
                          ConstantDefine.DEFINE_BUFF_SUB_TYPE_GOD]
# 回合开始结算类型
BUFF_CLEARING_TYPE_ROUND_START = [ConstantDefine.DEFINE_BUFF_SUB_TYPE_RECOVER_HP,
                                  ConstantDefine.DEFINE_BUFF_SUB_TYPE_REDUCE_HP,
                                  ConstantDefine.DEFINE_BUFF_SUB_TYPE_RECOVER_MP,
                                  ConstantDefine.DEFINE_BUFF_SUB_TYPE_REDUCE_MP,
                                  ConstantDefine.DEFINE_BUFF_SUB_TYPE_VERTIGO]
# 战斗被击结算类型
BUFF_CLEARING_TYPE_BY_ATK = [ConstantDefine.DEFINE_BUFF_SUB_TYPE_ATK_RECOVER_HP,
                             ConstantDefine.DEFINE_BUFF_SUB_TYPE_ATK_RECOVER_MP,
                             ConstantDefine.DEFINE_BUFF_SUB_TYPE_HRUT_ATK,
                             ConstantDefine.DEFINE_BUFF_SUB_TYPE_RE_ATK]


class BattleStateMachine:
    """战斗状态机"""
    MAXBUFNUM = 6  # 每个角色最多的buf个数

    def __init__(self, owner=None):
        """战斗状态机
        @param fight: Fight object 战斗实例
        """
        self.StatePool = {}
        self.owner = owner  # 状态池，保存战斗角色的buff状态

    def addNewBuff(self, targetId, buffId, actorId, skillHurt=0):
        """添加新的buff
        @param targetId :int 目标位置ID
        @param buffId:int buffID
        @param actorId:int 发起者位置ID
        """
        if buffId not in s_skillBuff.datas.keys():
            return

        if targetId in self.StatePool.keys():
            if buffId in self.StatePool[targetId].keys():
                stateBuff = self.StatePool[targetId].get(buffId)
                stateBuff.addStack()
                return
        else:
            self.StatePool[targetId] = {}

        newbuff = StateBuffer(buffId, holder=targetId, executor=actorId, skillHurt=skillHurt)
        self.StatePool[targetId][buffId] = newbuff

    def checkIsExistBuff(self, target, buffID):
        """检测BUFF是否存在"""
        if target not in self.StatePool.keys():
            return False
        if buffID in self.StatePool[target].keys():
            return True
        return False

    def clearBuffById(self, target, buffID):
        """根据buff的ID清除buff
        """
        if target not in self.StatePool.keys():
            return
        if buffID in self.StatePool[target].keys():
            del self.StatePool[target][buffID]

    def clearAllBuff(self, target):
        """删除所有BUFF"""
        if target not in self.StatePool.keys():
            return
        self.StatePool.pop(target)

    def getTargetAttrWithBuf(self, target):
        """获取角色的伴随buff后的属性
        @param target: int 目标在战场中的id
        """
        return copy.deepcopy(self.owner.fighters[target])

    def getTargeBuff(self, target, skillBuffId):
        """获取目标BUFF"""
        if target in self.StatePool.keys():
            return self.StatePool[target].get(skillBuffId)
        return None

    def getTargetBuffList(self, target):
        """获取目标的bufflist
        @param target: int 目标的id
        """
        buffList = []
        if target in self.StatePool.keys():
            buffList = self.StatePool[target].values()
        return buffList

    def getTargetBuffIDList(self, target):
        """获取目标的bufflist
        @param target: int 目标的id
        """
        buffIDList = []
        if target in self.StatePool.keys():
            buffIDList = self.StatePool[target].keys()
        return buffIDList

    def buffDeductHp(self, fighterId, data, hpValue, buffId):
        """BUFF扣除生命"""
        data['buffEffect'].append(
            {'BUFFId': buffId, 'EffectType': dbSkill.DEFINE_BUFF_SUB_TYPE_REDUCE_HP, 'EffectSubType': 0,
             'EffectValue': hpValue})
        self.owner.deductHp(data, fighterId, hpValue)

    def buffRecoverHp(self, fighterId, data, hpValue, buffId):
        """BUFF恢复生命"""
        data['buffEffect'].append(
            {'BUFFId': buffId, 'EffectType': dbSkill.DEFINE_BUFF_SUB_TYPE_RECOVER_HP, 'EffectSubType': 0,
             'EffectValue': hpValue})
        self.owner.recoverHp(data, fighterId, hpValue)

    def buffRecoverMp(self, fighterId, data, mpValue, buffId):
        """buff恢复怒气"""
        data['buffEffect'].append(
            {'BUFFId': buffId, 'EffectType': dbSkill.DEFINE_BUFF_SUB_TYPE_RECOVER_MP, 'EffectSubType': 0,
             'EffectValue': mpValue})
        self.owner.recoverMp(data, fighterId, mpValue)

    def buffDeductMp(self, fighterId, data, mpValue, buffId):
        """BUFF扣除怒气"""
        data['buffEffect'].append(
            {'BUFFId': buffId, 'EffectType': dbSkill.DEFINE_BUFF_SUB_TYPE_REDUCE_MP, 'EffectSubType': 0,
             'EffectValue': mpValue})
        self.owner.deductMp(data, fighterId, mpValue)

    def buffAppendDeHpRecover(self, fighterId, deHpRecoverValue, isPercent=False):
        """附加削弱HP恢复数值"""
        if isPercent:
            self.owner.fighters[fighterId]['deHpRecoverPercent'] = deHpRecoverValue
        else:
            self.owner.fighters[fighterId]['deHpRecover'] = deHpRecoverValue

    def buffSkipFight(self, data, buffId):
        """buff眩晕"""
        data['buffEffect'].append(
            {'BUFFId': buffId, 'EffectType': dbSkill.DEFINE_BUFF_SUB_TYPE_VERTIGO, 'EffectSubType': 0,
             'EffectValue': 0})
        data['skipAtk'] = 1

    def buffBeAtkRecoverHp(self, fighterId, data, hpValue, buffId):
        """被击恢复生命"""
        data['enemyChaArr'][fighterId]['buffEffect'].append(
            {'BUFFId': buffId, 'EffectType': dbSkill.DEFINE_BUFF_SUB_TYPE_ATK_RECOVER_HP, 'EffectSubType': 0,
             'EffectValue': hpValue})
        self.owner.recoverHp(data, fighterId, hpValue)

    def buffBeAtkRecoverMp(self, fighterId, data, mpValue, buffId):
        """被击恢复怒气"""
        data['enemyChaArr'][fighterId]['buffEffect'].append(
            {'BUFFId': buffId, 'EffectType': dbSkill.DEFINE_BUFF_SUB_TYPE_ATK_RECOVER_MP, 'EffectSubType': 0,
             'EffectValue': mpValue})
        self.owner.recoverMp(data, fighterId, mpValue)

    def buffAddArmor(self, fighterId, data, armorValue):
        """增加护甲"""
        self.owner.fighters[fighterId]['armor'] = armorValue
        if fighterId in data['enemyChaArr'].keys():
            data['enemyChaArr'][fighterId]['armor'] = self.owner.fighters[fighterId]['armor']
        if data['chaId'] == fighterId:
            data['armor'] = self.owner.fighters[fighterId]['armor']

    def calculateBuffEffectValue(self, target, buffSubType, buffValueType, buffValue, buffHurtValue):
        """计算BUFF效果数值"""
        if buffValueType == ConstantDefine.DEFINE_BUFF_VALUE_TYPE_FIXED:
            return buffValue
        elif buffValueType == ConstantDefine.DEFINE_BUFF_VALUE_TYPE_HURT:
            return buffHurtValue
        elif buffValueType == ConstantDefine.DEFINE_BUFF_VALUE_TYPE_PERCENT_HURT:
            return int(round(buffHurtValue * buffValue * 0.01))
        elif buffValueType == ConstantDefine.DEFINE_BUFF_VALUE_TYPE_PERCENT:
            if buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_RECOVER_HP or \
                    buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_REDUCE_HP or \
                    buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_ATK_RECOVER_HP:
                return int(round(self.owner.fighters[target]['chaMaxHp'] * buffValue * 0.01))
            elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_RECOVER_MP or \
                    buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_REDUCE_MP or \
                    buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_ATK_RECOVER_MP:
                return int(round(self.owner.fighters[target]['chaMaxMp'] * buffValue * 0.01))
            else:
                return 0
        else:
            return 0

    def executeBuffEffects(self, target, data):
        """进行buff效果(回合开始类型)
        @param target: int 目标的id
        @return: bool True :继续攻击 False:有禁止攻击BUFF 跳过本轮攻击
        """
        stateBuffList = self.getTargetBuffList(target)
        bCanDoSkill = True
        for stateBuff in stateBuffList:
            buffSubType = stateBuff.getSubType()
            if buffSubType not in BUFF_CLEARING_TYPE_ROUND_START:
                continue
            buffValueType = stateBuff.getValueType()
            buffValue = stateBuff.getValue()
            buffHurtValue = stateBuff.getSkillHurt()
            effectValue = self.calculateBuffEffectValue(target, buffSubType, buffValueType, buffValue, buffHurtValue)

            if buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_RECOVER_HP:
                self.buffRecoverHp(target, data, effectValue, stateBuff.getID())
            elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_REDUCE_HP:
                self.buffDeductHp(target, data, effectValue, stateBuff.getID())
            elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_RECOVER_MP:
                self.buffRecoverMp(target, data, effectValue, stateBuff.getID())
            elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_REDUCE_MP:
                self.buffDeductMp(target, data, effectValue, stateBuff.getID())
            elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_VERTIGO and \
                    self.owner.fighters[target]['canBeDizziness'] == 0:
                self.buffSkipFight(data, stateBuff.getID())
                bCanDoSkill = False
        return bCanDoSkill

    def executeBuffEffectsByAtk(self, target, data, skillHurt):
        """被击BUFF生效"""
        stateBuffList = self.getTargetBuffList(target)
        for stateBuff in stateBuffList:
            buffSubType = stateBuff.getSubType()
            if buffSubType not in BUFF_CLEARING_TYPE_BY_ATK:
                continue
            buffValueType = stateBuff.getValueType()
            buffValue = stateBuff.getValue()
            buffHurtValue = stateBuff.getSkillHurt()
            # 特殊处理伤害反弹
            if buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_HRUT_ATK:
                reAtkValue = 0
                if buffValueType == ConstantDefine.DEFINE_BUFF_VALUE_TYPE_FIXED:
                    reAtkValue += buffValue
                elif buffValueType == ConstantDefine.DEFINE_BUFF_VALUE_TYPE_PERCENT_HURT:
                    reAtkValue += int(round(skillHurt * buffValue * 0.01))
                elif buffValueType == ConstantDefine.DEFINE_BUFF_VALUE_TYPE_HURT:
                    reAtkValue += skillHurt
                self.owner.deductHp(data, data['chaId'], reAtkValue)
                continue
            effectValue = self.calculateBuffEffectValue(target, buffSubType, buffValueType, buffValue, buffHurtValue)
            if buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_ATK_RECOVER_HP:
                self.buffBeAtkRecoverHp(target, data, effectValue, stateBuff.getID())
            elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_ATK_RECOVER_MP:
                self.buffBeAtkRecoverMp(target, data, effectValue, stateBuff.getID())

    def executeBuffEffectsNew(self, target, data, skillBuffId):
        """新增BUFF生效"""
        # 计算属性强化类BUFF
        self.calculateAttributeBuff(target, skillBuffId)
        # 计算削弱生命恢复,增加护甲,伤害免疫
        stateBuff = self.getTargeBuff(target, skillBuffId)
        if not stateBuff:
            return

        buffSubType = stateBuff.getSubType()
        buffValueType = stateBuff.getValueType()
        buffValue = stateBuff.getValue()
        buffHurtValue = stateBuff.getSkillHurt()
        effectValue = self.calculateBuffEffectValue(target, buffSubType, buffValueType, buffValue, buffHurtValue)
        if buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_ADD_ARMOR:
            self.buffAddArmor(target, data, effectValue)
        elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_WEAKEN_RECOVER_HP:
            self.buffAppendDeHpRecover(target, effectValue, {1: True, 2: False}.get(buffValueType))
        elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_GOD:
            self.owner.fighters[target]['canBeNotHurt'] = 1
            if target in data['enemyChaArr'].keys():
                data['enemyChaArr'][target]['canBeNotHurt'] = self.owner.fighters[target]['canBeNotHurt']
            if data['chaId'] == target:
                data['canBeNotHurt'] = self.owner.fighters[target]['canBeNotHurt']

    def ClearBuffEffect(self, target, stateBuff):
        """清除BUFF效果"""
        buffSubType = stateBuff.getSubType()
        buffValueType = stateBuff.getValueType()
        if buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_ADD_ARMOR:
            self.owner.fighters[target]['armor'] = 0
            # if target in data['enemyChaArr'].keys():
            #     data['enemyChaArr'][target]['armor'] = self.owner.fighters[target]['armor']
            # if data['chaId'] == target:
            #     data['armor'] = self.owner.fighters[target]['armor']
        elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_WEAKEN_RECOVER_HP:
            self.buffAppendDeHpRecover(target, 0, {1: True, 2: False}.get(buffValueType))
        elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_GOD:
            self.owner.fighters[target]['canBeNotHurt'] = 0
            # if target in data['enemyChaArr'].keys():
            #     data['enemyChaArr'][target]['canBeNotHurt'] = self.owner.fighters[target]['canBeNotHurt']
            # if data['chaId'] == target:
            #     data['canBeNotHurt'] = self.owner.fighters[target]['canBeNotHurt']

    def calculateAttributeBuffClear(self, actorId, buffId):
        """清除属性强化类BUFF"""
        if buffId in self.owner.fighters[actorId]['buffEffects'].keys():
            for addBuffValue in self.owner.fighters[actorId]['buffEffects'][buffId]:
                addAttributeKey = addBuffValue['buffAttType']
                addValue = addBuffValue['buffAttValue']
                self.owner.fighters[actorId][addAttributeKey] -= addValue
                self.owner.fighters[actorId]['buffEffects'][buffId].remove(addBuffValue)
            if len(self.owner.fighters[actorId]['buffEffects'][buffId]) == 0:
                self.owner.fighters[actorId]['buffEffects'].pop(buffId)
        self.clearBuffById(actorId, buffId)

    def calculateAttributeBuff(self, actorId, skillBuffId):
        """属性强化类BUFF计算"""
        fightAttributeKey = {1: {1: ['physicalAttack', 'physicalAttackMax'], 2: ['scAttack', 'scAttackMax'],
                                 3: ['magicAttack', 'magicAttackMax'], \
                                 4: ['physicalAttack', 'physicalAttackMax'], 5: ['scAttack', 'scAttackMax'],
                                 6: ['magicAttack', 'magicAttackMax']},
                             2: ['physicalDefense', 'physicalDefenseMax', 'magicDefense', 'magicDefenseMax'],
                             3: ['critRate'],
                             4: ['hitRate'],
                             5: ['dodgeRate'],
                             6: ['toughness'],
                             7: ['chaMaxHp']}
        stateBuff = self.getTargeBuff(actorId, skillBuffId)

        buffSubType = stateBuff.getSubType()
        if buffSubType not in BUFF_CLEARING_TYPE_NEW:
            return
        buffAttType = stateBuff.getAttType()
        buffValueType = stateBuff.getValueType()
        buffValue = stateBuff.getValue()
        if buffAttType not in fightAttributeKey.keys() or \
                ConstantDefine.DEFINE_BUFF_VALUE_TYPE_FIXED < buffValueType < \
                ConstantDefine.DEFINE_BUFF_VALUE_TYPE_PERCENT:
            return
        # 1:攻击 2:防御 3:暴击 4命中 5:闪避 6:韧性 7:血量
        addAttributeKey = fightAttributeKey.get(buffAttType, [])
        if not addAttributeKey:
            return
        addAttributeKeyList = []
        if buffAttType == 1:
            addAttributeKeyList.extend(addAttributeKey[self.owner.fighters[actorId]['chaProfessionType']])
        else:
            addAttributeKeyList.extend(addAttributeKey)

        addValue = 0
        for addAttributeKey in addAttributeKeyList:
            if buffValueType == ConstantDefine.DEFINE_BUFF_VALUE_TYPE_FIXED:  # 数值
                if buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_ADD_ATT:
                    addValue = buffValue * stateBuff.getStack()
                    self.owner.fighters[actorId][addAttributeKey] += addValue
                elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_REDUCE_ATT:
                    addValue = -buffValue * stateBuff.getStack()
                    self.owner.fighters[actorId][addAttributeKey] += addValue
            elif buffValueType == ConstantDefine.DEFINE_BUFF_VALUE_TYPE_PERCENT:  # 百分比
                if buffSubType == dbSkiConstantDefinell.DEFINE_BUFF_SUB_TYPE_ADD_ATT:
                    addValue = int(self.owner.fighters[actorId][addAttributeKey] * buffValue * 0.01)
                elif buffSubType == ConstantDefine.DEFINE_BUFF_SUB_TYPE_REDUCE_ATT:
                    addValue = -int(self.owner.fighters[actorId][addAttributeKey] * buffValue * 0.01)
                addValue *= stateBuff.getStack()
                # log.msg("calculateAttributeBuff:actorId:%s,key:%s,value:%s,oldValue:%s"%(actorId,addAttributeKey,addValue,self.owner.fighters[actorId][addAttributeKey]))
                self.owner.fighters[actorId][addAttributeKey] += addValue
                # log.msg("calculateAttributeBuff:actorId:%s,key:%s,value:%s,newValue:%s"%(actorId,addAttributeKey,addValue,self.owner.fighters[actorId][addAttributeKey]))
            if self.owner.fighters[actorId][addAttributeKey] < 0:
                addValue -= self.owner.fighters[actorId][addAttributeKey]
                self.owner.fighters[actorId][addAttributeKey] = 0

            if stateBuff.getID() not in self.owner.fighters[actorId]['buffEffects'].keys():
                self.owner.fighters[actorId]['buffEffects'][stateBuff.getID()] = []
            self.owner.fighters[actorId]['buffEffects'][stateBuff.getID()].append(
                {'buffAttType': addAttributeKey, 'buffAttValue': addValue})

    def cutBuffTraceCD(self, actorId):
        """减少BUFFCD"""
        stateBuffList = self.getTargetBuffList(actorId)
        for stateBuff in stateBuffList:
            stateBuff.cutTraceCD()

    def checkBuffCD(self, actorId):
        """检测BUFFCD"""
        stateBuffList = self.getTargetBuffList(actorId)
        for stateBuff in stateBuffList:
            if stateBuff.getTraceCD() <= 0:
                buffSubType = stateBuff.getSubType()
                if buffSubType <= ConstantDefine.DEFINE_BUFF_SUB_TYPE_REDUCE_ATT:
                    self.calculateAttributeBuffClear(actorId, stateBuff.getID())
                    continue
                self.ClearBuffEffect(actorId, stateBuff)
                self.clearBuffById(actorId, stateBuff.getID())
